package com.zxy.zxyrpc.serializer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zxy.zxyrpc.model.RpcRequest;
import com.zxy.zxyrpc.model.RpcResponse;

import java.io.IOException;

/**
 * json 序列化器类（实现相对复杂，需要考虑兼容性问题，复杂数据结构丢失泛型。如：Object数组在序列化后会丢失类型）
 *
 * @author zxy
 * @since 2025/5/11
 **/
public class JsonSerializer implements Serializer {
    // json 序列化器
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public <T> byte[] serialize(T object) throws IOException {
        return OBJECT_MAPPER.writeValueAsBytes(object);
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {
        T obj = OBJECT_MAPPER.readValue(bytes, type);
        // 处理类型丢失问题
        if (obj instanceof RpcRequest)
            return handleRequest((RpcRequest) obj, type);
        if (obj instanceof RpcResponse)
            return handleResponse((RpcResponse) obj, type);
        return obj;
    }

    /**
     * @param rpcResponse rpc 响应
     * @param type        响应类型
     */
    private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        byte[] bytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        rpcResponse.setData(OBJECT_MAPPER.readValue(bytes, rpcResponse.getDateType()));
        return type.cast(rpcResponse);
    }

    /**
     * json 序列化时，由于Object的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap 无法转换成原始对象，因此需要特殊处理
     *
     * @param rpcRequest rpc 请求
     * @param type       序列化后的类型
     */
    private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();

        // 循环处理每个类型的参数
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> clazz = parameterTypes[i];
            // 类型不同，重新处理
            if (!clazz.isAssignableFrom(args[i].getClass())) {
                byte[] argBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);
                args[i] = OBJECT_MAPPER.readValue(argBytes, clazz);
            }
        }
        return type.cast(rpcRequest);
    }
}
